using ChromeTabs;
using JiveMessenger.Models;
using JiveMessenger.AvalonEdit;
using JiveMessenger.User;
using JmShared;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using System.Linq;
using System;
using System.Windows.Input;
using System.Collections.ObjectModel;
using JiveMessenger.Utilities;
using System.ComponentModel;
using System.Windows.Data;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Windows;
using System.Threading.Tasks;


namespace JiveMessenger.ViewModels
{
    public class ViewModelMainWindow : ViewModelBase, IViewModelMainWindow
    {
        private DateTime _lastShowHideContactListTime;
        private IClient _currentClient;
        private object LockObject = new object();
        public RelayCommand EditFontCommand { get; set; }
        public RelayCommand GetEmoticonsCommand { get; set; }
        public RelayCommand<bool> LogoutCommand { get; set; }
        public RelayCommand OpenOptionsCommand { get; set; }
        public RelayCommand ViewLogCommand { get; set; }
        public RelayCommand WindowLoadedCommand { get; set; }
        public RelayCommand<KeyEventArgs> PreviewKeyUpCommand { get; set; }
        public RelayCommand HideMenuCommand { get; set; }
        public RelayCommand OpenContactListWindowCommand { get; set; }
        public RelayCommand<object> ShowHideContactlistCommand { get; set; }
        public RelayCommand<ViewModelTab> CloseTabCommand { get; set; }
        public RelayCommand<TabReorder> TabsReorderedCommand { get; set; }
        public RelayCommand OpenNotificationsWindowCommand { get; set; }
        public RelayCommand CloseNotificationsBarCommand { get; set; }
        public RelayCommand<ViewModelTab> CloseAllTabsCommand { get; set; }
        public RelayCommand<ViewModelTab> PinTabCommand { get; set; }
        public RelayCommand StartUpdateCheckCommand { get; set; }
        public RelayCommand ShowAboutWindowCommand { get; set; }
        public RelayCommand OpenWelcomeTabCommand { get; set; }

        private ObservableCollection<ViewModelTab> _chatViewModels;
        public ObservableCollection<ViewModelTab> ChatViewModels
        {
            get { return _chatViewModels; }
            set
            {
                if (_chatViewModels != value)
                {
                    if (_chatViewModels != null)
                        _chatViewModels.CollectionChanged -= ChatViewModels_CollectionChanged;
                    Set(() => ChatViewModels, ref _chatViewModels, value);
                    if (_chatViewModels != null)
                        _chatViewModels.CollectionChanged += ChatViewModels_CollectionChanged;
                }
            }
        }

        private ViewModelTab _currentActiveViewModel;
        public ViewModelTab CurrentActiveViewModel
        {
            get { return _currentActiveViewModel; }
            set
            {
                if (_currentActiveViewModel != value)
                {
                    if (_currentActiveViewModel != null)
                        _currentActiveViewModel.IsCurrentActiveTab = false;

                    Set(() => CurrentActiveViewModel, ref _currentActiveViewModel, value);

                    if (_currentActiveViewModel != null)
                        _currentActiveViewModel.IsCurrentActiveTab = true;

                    if (value == null)
                        IsChatControlVisible = false;
                    else
                    {
                        IsChatControlVisible = true;
                        value.IsBlinking = false;
                    }
                }
            }
        }
        private bool _isMainMenuVisible;
        public bool IsMainMenuVisible
        {
            get { return _isMainMenuVisible; }
            set
            {
                if (_isMainMenuVisible != value)
                {
                    Set(() => IsMainMenuVisible, ref _isMainMenuVisible, value);
                }
            }
        }

        private string _windowTitle;
        public string WindowTitle
        {
            get { return _windowTitle; }
            set
            {
                if (_windowTitle != value)
                {
                    Set(() => WindowTitle, ref _windowTitle, value);
                }
            }
        }

        private bool _isLoginControlVisible;
        public bool IsLoginControlVisible
        {
            get { return _isLoginControlVisible; }
            set
            {
                if (_isLoginControlVisible != value)
                {
                    Set(() => IsLoginControlVisible, ref _isLoginControlVisible, value);
                }
            }
        }

        private bool _isChatControlVisible;
        public bool IsChatControlVisible
        {
            get { return _isChatControlVisible; }
            set
            {
                if (_isChatControlVisible != value)
                {
                    Set(() => IsChatControlVisible, ref _isChatControlVisible, value);
                }
            }
        }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public ViewModelMainWindow(IClient currentClient)
        {
            IsLoginControlVisible = true;
            if (IsInDesignMode)
            {
            }
            else
            {
                this._currentClient = currentClient;
                this.IsMainMenuVisible = false;
                this.WindowTitle = "Jive Messenger";
                this.ChatViewModels = new SortedObservableCollection<ViewModelTab>();
                this.GetEmoticonsCommand = new RelayCommand(GetEmoticonsCommandAction, () => _currentClient.IsLoggedIn);
                this.LogoutCommand = new RelayCommand<bool>(LogoutCommandAction, (x) => _currentClient.IsLoggedIn);
                this.OpenOptionsCommand = new RelayCommand(OpenOptionsCommandAction, () => _currentClient.IsLoggedIn);
                this.ViewLogCommand = new RelayCommand(ViewLogCommandAction, () => _currentClient.IsLoggedIn);
                this.PreviewKeyUpCommand = new RelayCommand<KeyEventArgs>(PreviewKeyUpCommandAction);
                this.WindowLoadedCommand = new RelayCommand(WindowLoadedCommandAction);
                this.HideMenuCommand = new RelayCommand(HideMenuCommandAction);
                this.OpenContactListWindowCommand = new RelayCommand(OpenContactListWindowCommandAction, () => _currentClient.IsLoggedIn);
                this.EditFontCommand = new RelayCommand(EditFontCommandAction, () => _currentClient.IsLoggedIn);
                this.ShowHideContactlistCommand = new RelayCommand<object>(ShowHideContactlistCommandAction);//, (obj) => _currentClient.IsLoggedIn);
                this.TabsReorderedCommand = new RelayCommand<TabReorder>(TabsReorderedCommandAction, (reorder) => _currentClient.IsLoggedIn);
                this.OpenNotificationsWindowCommand = new RelayCommand(OpenNotificationsWindowCommandAction, () => _currentClient.IsLoggedIn);
                this.CloseNotificationsBarCommand = new RelayCommand(CloseNotificationsBarCommandAction);
                this.CloseTabCommand = new RelayCommand<ViewModelTab>(CloseTabCommandAction, (tab) => _currentClient.IsLoggedIn);
                this.CloseAllTabsCommand = new RelayCommand<ViewModelTab>(CloseAllTabsCommandAction, (tab) => _currentClient.IsLoggedIn);
                this.PinTabCommand = new RelayCommand<ViewModelTab>(PinTabCommandAction, (tab) => _currentClient.IsLoggedIn);
                this.StartUpdateCheckCommand = new RelayCommand(StartUpdateCheckCommandAction);
                this.ShowAboutWindowCommand = new RelayCommand(ShowAboutWindowCommandAction);
                this.OpenWelcomeTabCommand = new RelayCommand(OpenWelcomeTabCommandAction, () => _currentClient.IsLoggedIn);

                ICollectionView view = CollectionViewSource.GetDefaultView(this.ChatViewModels) as ICollectionView;

                view.Filter = model =>
                    {
                        if (model is ViewModelChat)
                            return ((ViewModelChat)model).ShowAsTab;
                        else
                            return true;
                    };
                view.SortDescriptions.Add(new SortDescription("TabNumber", ListSortDirection.Ascending));

                Messenger.Default.Register<NotificationMessage<ViewModelChat>>(this, msg =>
                    {
                        switch (msg.Notification)
                        {
                            case "OpenGroup":
                                OpenGroup(msg.Content as ViewModelChat);
                                break;
                        }
                    });
                Messenger.Default.Register<NotificationMessage<string>>(this, msg =>
                    {
                        switch (msg.Notification)
                        {
                            case "CloseTab":
                                ViewModelTab tab = ChatViewModels.FirstOrDefault(x => x.ID == msg.Content);
                                if (tab != null)
                                {
                                    CloseTabCommand.Execute(tab);
                                }
                                break;
                        }
                    });
                Messenger.Default.Register<NotificationMessage<IContact>>(this, msg =>
                    {
                        switch (msg.Notification)
                        {
                            case "UpdateConversationLineTransformers":
                                UpdateConversationLineTransformers(msg.Content as IContact);
                                break;
                        }
                    });
            }
        }

        private void OpenWelcomeTabCommandAction()
        {
            ViewModelWelcomeInfo welcomeTab = this.ChatViewModels.FirstOrDefault(x => x is ViewModelWelcomeInfo) as ViewModelWelcomeInfo;
            if (welcomeTab == null)
            {
                welcomeTab = new ViewModelWelcomeInfo();
                this.ChatViewModels.Add(welcomeTab);
            }

            CurrentActiveViewModel = welcomeTab;
        }

        private void ShowAboutWindowCommandAction()
        {
            Messenger.Default.Send(new NotificationMessage(this, "OpenAboutWindow"));
        }

        private void StartUpdateCheckCommandAction()
        {
            Properties.Settings.Default.SkipUpdateVersion = string.Empty;
            Messenger.Default.Send(new NotificationMessage(this, "StartUpdateCheck"));
        }

        private void UpdateConversationLineTransformers(IContact contact)
        {
            foreach (ViewModelChat vm in ChatViewModels.Where(x => x is ViewModelChat))
            {
                LineColorizer lc = (LineColorizer)vm.ConversationLineTransformers.FirstOrDefault(x => x is LineColorizer && ((LineColorizer)x).UserInfo.UserID == contact.UserID);
                if (lc == null)
                {
                    lc = new LineColorizer(contact, vm.ClientLines);
                    vm.ConversationLineTransformers.Add(lc);
                }
                else
                    lc.UserInfo = contact;
            }
        }

        private void OpenGroup(ViewModelChat vm)
        {
            ViewModelChat existingchat = ChatViewModels.FirstOrDefault(x => x.ID == vm.ID) as ViewModelChat;
            if (existingchat == null)
            {
                ChatViewModels.Add(vm);
                CurrentActiveViewModel = vm;
            }
            else
            {
                CurrentActiveViewModel = existingchat;
            }
        }

        private void PinTabCommandAction(ViewModelTab tabToPin)
        {
            if (tabToPin == null)
                return;
            tabToPin.IsPinned = !tabToPin.IsPinned;
            RaisePropertyChanged("CurrentActiveViewModel");
        }

        /// <summary>
        /// Close all tabs, with optional tab to keep open
        /// </summary>
        /// <param name="tabToKeep"></param>
        private void CloseAllTabsCommandAction(ViewModelTab tabToKeep)
        {
            var tabs = new List<ViewModelTab>(this.ChatViewModels);
            foreach (ViewModelTab tab in tabs)
            {
                if (tabToKeep != null && tabToKeep.Equals(tab))
                    continue;
                this.CloseTabCommand.Execute(tab);
            }
        }


        private void CloseNotificationsBarCommandAction()
        {
            Messenger.Default.Send(new NotificationMessage(this, "MarkAllNotificationsAsRead"));
        }

        private void OpenNotificationsWindowCommandAction()
        {
            Messenger.Default.Send(new NotificationMessage(this, "OpenNotifications"));
        }

        private void TabsReorderedCommandAction(TabReorder reorder)
        {
            ICollectionView view = CollectionViewSource.GetDefaultView(this.ChatViewModels) as ICollectionView;
            int from = reorder.FromIndex;
            int to = reorder.ToIndex;
            var sourceCol = view.SourceCollection.Cast<ViewModelTab>().OrderBy(x => x.TabNumber).ToList();
            sourceCol[from].TabNumber = sourceCol[to].TabNumber;
            if (to > from)
            {
                for (int i = from + 1; i <= to; i++)
                {
                    sourceCol[i].TabNumber--;
                }
            }
            else if (from > to)
            {
                for (int i = to; i < from; i++)
                {
                    sourceCol[i].TabNumber++;
                }
            }
            view.Refresh();
        }

        void ChatViewModels_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            ObservableCollection<ViewModelTab> chatViewModels = (ObservableCollection<ViewModelTab>)sender;
            foreach (var item in chatViewModels)
            {
                item.TabNumber = chatViewModels.IndexOf(item);
            }
            if (chatViewModels.Count == 0 && e.OldItems!= null && e.OldItems.Count>0)
                ShowHideContactlistCommand.Execute(null);
        }

        private void CloseTabCommandAction(ViewModelTab vm)
        {
            if (vm == null)
                vm = this.CurrentActiveViewModel;

            this.ChatViewModels.Remove(vm);

            if (vm is ViewModelChat)
            {
                Task t = Task.Factory.StartNew((obj) =>
                    {
                        ViewModelChat chatVM = obj as ViewModelChat;
                        chatVM.WriteLog();
                        chatVM.RemainingMessages = 0;
                        chatVM.IsBlinking = false;
                        chatVM.IsCurrentActiveTab = false;
                        //chatVM.Cleanup();
                        _currentClient.ClosedConversations[chatVM.ID] = chatVM;

                    }, vm);
            }
        }

        private void ShowHideContactlistCommandAction(object value)
        {
            if (DateTime.Now.Subtract(_lastShowHideContactListTime).TotalMilliseconds < 300)
                return;
            _lastShowHideContactListTime = DateTime.Now;
            bool result;
            if (value != null && Boolean.TryParse(value.ToString(), out result))
            {
                if (result != Properties.Settings.Default.SettingIsContactListVisible)
                    Properties.Settings.Default.SettingIsContactListVisible = result;
            }
            else
                Properties.Settings.Default.SettingIsContactListVisible = !Properties.Settings.Default.SettingIsContactListVisible;
        }

        private void EditFontCommandAction()
        {
            Messenger.Default.Send<NotificationMessage>(new NotificationMessage(this, "ChangeFont"));
        }

        private void OpenContactListWindowCommandAction()
        {
            Messenger.Default.Send(new NotificationMessage(this, "OpenContactListWindow"));
        }

        private void GetEmoticonsCommandAction()
        {
            Messenger.Default.Send<NotificationMessage>(new NotificationMessage(this, "AddUserEmoticons"));
        }

        private void HideMenuCommandAction()
        {
            IsMainMenuVisible = false;
        }

        private void PreviewKeyUpCommandAction(KeyEventArgs e)
        {
            if ((e.SystemKey == Key.LeftAlt || e.SystemKey == Key.RightAlt) && Properties.Settings.Default.SettingEnableMainMenu)
            {
                IsMainMenuVisible = !IsMainMenuVisible;
            }
        }

        private void WindowLoadedCommandAction()
        {
            if (Properties.Settings.Default.LoginAutomatically)
            {
                if (String.IsNullOrEmpty(Properties.Settings.Default.Server))
                    return;
                _currentClient.StartConnectTask(true);
            }
        }

        private void ViewLogCommandAction()
        {
            foreach (var vm in this.ChatViewModels.Where(x => x is ViewModelChat).Cast<ViewModelChat>())
            {
                vm.WriteLog();
            }
            Messenger.Default.Send(new NotificationMessage(this, "OpenLogs"));
        }

        private void OpenOptionsCommandAction()
        {
            Messenger.Default.Send(new NotificationMessage(this, "OpenOptions"));
        }

        private void LogoutCommandAction(bool isExit)
        {
            _currentClient.StopReconnectRetrying = true;
            _currentClient.IsUserConnecting = !isExit;

            _currentClient.UserSettings.OpenChats = this.ChatViewModels.
                    Where(vm => vm.GetType() == typeof(ViewModelGroupChat)).
                    Select(vm => new OpenChat(vm.ID, vm.IsPinned, ChatType.GroupChat)).
                Union<OpenChat>(this.ChatViewModels.
                    Where(vm => vm.GetType() == typeof(ViewModelPrivateMessage)).
                    Select(vm => new OpenChat(vm.ID, vm.IsPinned, ChatType.PrivateMessage))).ToList();

            foreach (var vm in ChatViewModels.Where(x => x is ViewModelChat).Cast<ViewModelChat>())
            {
                vm.WriteLog();
                vm.Cleanup();
            }
            Messenger.Default.Send<NotificationMessage>(new NotificationMessage(this, "ClosePmWindows"));
            _currentClient.Connection.SendMessage(new ChatMessage(_currentClient.CurrentUserInfo, MessageType.UpdateNotifications));
            _currentClient.Connection.SendCommand(_currentClient.UserSettings, ClientCommands.PcSettings);
            _currentClient.Connection.Logout();
        }

        public override void Cleanup()
        {


            Application.Current.Dispatcher.Invoke(() =>
                {
                    this.CurrentActiveViewModel = null;
                    this.ChatViewModels.Clear();
                });
            // base.Cleanup();
        }

        public void RestoreTabs()
        {
            foreach (OpenChat openChat in _currentClient.UserSettings.OpenChats)
            {
                if (!this.ChatViewModels.Any(x => x.ID == openChat.ID))
                {
                    ViewModelChat vm = null;
                    if (!_currentClient.ClosedConversations.TryRemove(openChat.ID, out vm))
                    {
                        IContact currentUser = null;
                        Messenger.Default.Send(new NotificationMessageAction<IContact>("GetCurrentUserContact", msg => currentUser = msg));

                        if (openChat.Type == ChatType.GroupChat)
                        {
                            IChatGroup group = currentUser.ChatGroups.FirstOrDefault(x => x.ID == openChat.ID);
                            if (group != null)
                            {
                                vm = new ViewModelGroupChat(_currentClient, group, currentUser, true, false) { IsPinned = openChat.IsPinned };
                            }
                        }
                        else if (openChat.Type == ChatType.PrivateMessage)
                        {
                            //  var contact = locator.ViewModelContactList.Contacts.FirstOrDefault(x => x.UserName == openChat.ID);
                            Messenger.Default.Send(new NotificationMessageAction<IContact>(this, openChat.ID, "GetContactFromUsername", contact =>
                                {
                                    if (contact != null)
                                    {
                                        vm = new ViewModelPrivateMessage(_currentClient, contact, currentUser, true, false) { IsPinned = openChat.IsPinned };
                                    }
                                }));
                        }
                    }
                    if (vm != null)
                    {
                        this.ChatViewModels.Add(vm);
                    }
                }
            }
            CurrentActiveViewModel = this.ChatViewModels.FirstOrDefault();

            if (ProgramSettings.Instance.JustUpdated || this.ChatViewModels.Count == 0)
            {
                OpenWelcomeTabCommand.Execute(null);
                ProgramSettings.Instance.JustUpdated = false;
            }
            this.IsLoginControlVisible = false;
            IsChatControlVisible = true;
        }

        public void RunOnNetworkConnect()
        {
            if (!String.IsNullOrEmpty(_currentClient.CurrentUserInfo.NickName))
                this.WindowTitle = "Jive Messenger" + " - " + _currentClient.CurrentUserInfo.NickName + " <" + _currentClient.CurrentUserInfo.UserName + ">";
            else
                this.WindowTitle = "Jive Messenger" + " - " + _currentClient.CurrentUserInfo.UserName;

            Messenger.Default.Send(new NotificationMessage(this, "InitKeyBindings"));
        }

        public void RunOnNetworkDisconnect()
        {
            this.WindowTitle = "Jive Messenger";
            this.IsLoginControlVisible = true;
        }
    }
}